import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:ideology/shared/widgets/code_input/core/text_buffer.dart';
import 'package:ideology/shared/widgets/code_input/highlight/highlight_theme.dart';
import 'package:ideology/shared/widgets/code_input/highlight/syntax_highlighter.dart';

/// **代码编辑器的自定义绘制器 (CustomPainter)**。
///
/// - 负责绘制：
///   - 背景；
///   - 语法高亮的多行文本；
///   - 文本选区高亮背景；
///   - 光标。
///
/// - 内部依赖 [TextBuffer] 提供的内容、
///   [SyntaxHighlighter] 提供的高亮 token，
///   [HighlightTheme] 提供的文本样式。
///
/// - 使用场景：直接绑定到 `CustomPaint`，在 Flutter 编辑器/代码输入控件中渲染。
class EditorPainter extends CustomPainter {
  final TextBuffer buffer;       // 文本存储
  final double lineHeight;       // 行高（用于行间距和滚动计算）
  final double padding;          // 左右/上下边距
  final int cursorPos;           // 光标位置（绝对索引）
  final bool showCursor;         // 是否显示光标
  final int? selectionStart;     // 选区起始位置（绝对索引）
  final int? selectionEnd;       // 选区结束位置（绝对索引）
  final double scrollY;          // 垂直滚动偏移量（像素）

  final SyntaxHighlighter highlighter; // 语法高亮器
  final HighlightTheme theme;          // 高亮主题

  /// 用于测量文本宽度 & 绘制的核心工具。
  final TextPainter _tp = TextPainter(textDirection: ui.TextDirection.ltr);

  EditorPainter({
    required this.buffer,
    required this.lineHeight,
    required this.padding,
    required this.cursorPos,
    required this.showCursor,
    required this.selectionStart,
    required this.selectionEnd,
    required this.scrollY,
    required this.highlighter,
    required this.theme,
  });

  @override
  void paint(Canvas canvas, Size size) {
    // 背景填充为白色
    final bgPaint = Paint()..color = Colors.white;
    canvas.drawRect(Offset.zero & size, bgPaint);

    final lines = buffer.getLines();
    highlighter.rebuildIfNeeded(buffer);

    // 计算可见的行范围（基于滚动）
    final visibleTop = (scrollY / lineHeight).floor();
    final visibleCount = (size.height / lineHeight).ceil() + 2;
    final startRow = visibleTop.clamp(0, lines.length);
    final endRow = (visibleTop + visibleCount).clamp(0, lines.length);

    // 先绘制选区背景
    if (selectionStart != null && selectionEnd != null && selectionStart != selectionEnd) {
      _paintSelection(canvas, lines, startRow, endRow);
    }

    // 绘制每一行文本（语法高亮）
    for (int row = startRow; row < endRow; row++) {
      final line = lines[row];
      final spans = highlighter.buildSpansForLine(row, line);

      _tp.text = TextSpan(children: spans);
      _tp.layout(maxWidth: size.width - padding * 2);

      final dx = padding;
      final dy = padding + row * lineHeight - scrollY;
      _tp.paint(canvas, Offset(dx, dy));
    }

    // 绘制光标
    if (showCursor) {
      final rc = _calcRowCol(cursorPos, lines);
      final row = rc[0];
      final col = rc[1];
      if (row >= startRow && row < endRow) {
        final dx = padding + _measurePrefixWidth(lines[row], col);
        final dy = padding + row * lineHeight - scrollY;
        final cursorPaint = Paint()..color = Colors.black;
        canvas.drawRect(Rect.fromLTWH(dx, dy, 2, lineHeight), cursorPaint);
      }
    }
  }

  /// 测量某行从起点到 [col] 列的宽度。
  double _measurePrefixWidth(String line, int col) {
    final prefix = (col <= 0) ? '' : line.substring(0, col.clamp(0, line.length));
    _tp.text = TextSpan(text: prefix, style: theme.base);
    _tp.layout();
    return _tp.width;
  }

  /// 将绝对索引位置转换为行号 + 列号。
  ///
  /// 遍历所有行，累加长度，直到找到光标所在的行。
  List<int> _calcRowCol(int absolutePos, List<String> lines) {
    int pos = 0;
    for (int row = 0; row < lines.length; row++) {
      final len = lines[row].length;
      if (absolutePos <= pos + len) {
        return [row, absolutePos - pos];
      }
      pos += len + 1; // 加上 '\n'
    }
    // 如果超出范围，则定位到最后一行末尾
    final last = lines.isEmpty ? 0 : lines.length - 1;
    final col = lines.isEmpty ? 0 : lines.last.length;
    return [last, col];
  }

  /// 绘制选区背景（淡蓝色矩形覆盖）。
  void _paintSelection(Canvas canvas, List<String> lines, int startRow, int endRow) {
    final a0 = selectionStart!;
    final b0 = selectionEnd!;
    final a = a0 < b0 ? a0 : b0;
    final b = a0 < b0 ? b0 : a0;

    int abs = 0;
    final paint = Paint()..color = const Color(0x3381D4FA); // 半透明蓝色

    for (int row = 0; row < lines.length; row++) {
      final len = lines[row].length;
      final lineStart = abs;
      final lineEnd = abs + len;

      // Clamp 到当前行区间
      final s = a.clamp(lineStart, lineEnd);
      final e = b.clamp(lineStart, lineEnd);

      if (s < e && row >= startRow && row < endRow) {
        final startCol = s - lineStart;
        final endCol = e - lineStart;
        final y = padding + row * lineHeight - scrollY;
        final x1 = padding + _measurePrefixWidth(lines[row], startCol);
        final x2 = padding + _measurePrefixWidth(lines[row], endCol);
        canvas.drawRect(Rect.fromLTWH(x1, y, x2 - x1, lineHeight), paint);
      }

      abs = lineEnd + 1; // +1 for '\n'
    }
  }

  @override
  bool shouldRepaint(covariant EditorPainter old) {
    // 仅当缓冲区或状态变更时触发重绘
    final repaint =
        buffer.version != old.buffer.version ||
            cursorPos != old.cursorPos ||
            showCursor != old.showCursor ||
            selectionStart != old.selectionStart ||
            selectionEnd != old.selectionEnd ||
            scrollY != old.scrollY ||
            highlighter.version != old.highlighter.version;
    return repaint;
  }
}
